package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.HashMap;
import java.util.List;

import shared.PlayerPosition;

import deck.Card;
import deck.OutOfCardsException;
import deck.Suit;
import network.message.IMessage;
import network.message.IMessage.MessageType;
import network.message.Message;

public class SetbackServer {
	
	private SetbackMatch match;
	private ServerSocket socket;
	private int port = 5555;
	private HashMap<PlayerPosition, ObjectOutputStream> outputStreams;
	
	public SetbackServer()
	{
		outputStreams = new HashMap<PlayerPosition, ObjectOutputStream>();
		match = new SetbackMatch(this);
		match.addPlayer(new RobotPlayer(PlayerPosition.NORTH, "NorthBOT"));
		match.addPlayer(new RobotPlayer(PlayerPosition.EAST, "EastBOT"));
		match.addPlayer(new RobotPlayer(PlayerPosition.SOUTH, "SouthBOT"));
		match.addPlayer(new RobotPlayer(PlayerPosition.WEST, "WestBOT"));
		
	}
	
	public void initServer() throws IOException {
		socket = new ServerSocket(port);
		
		for (int i = 0; i < 4; i++) {
			Socket s = socket.accept();
			ServerThread t = new ServerThread(s, this);
			addOutputStream(s);
			t.start();
		}
	}
	
	/**
	 * Assigns the output stream to a player position.
	 * @param socket - the new players socket.
	 */
	private void addOutputStream(Socket socket)
	{
		PlayerPosition pos;
		if(!outputStreams.containsKey(PlayerPosition.NORTH))
		{
			pos = PlayerPosition.NORTH;
		}
		else if(!outputStreams.containsKey(PlayerPosition.EAST))
		{
			pos = PlayerPosition.EAST;
		}
		else if(!outputStreams.containsKey(PlayerPosition.SOUTH))
		{
			pos = PlayerPosition.SOUTH;
		}
		else
		{
			pos = PlayerPosition.WEST;
		}
		
		try 
		{
			outputStreams.put(pos, new ObjectOutputStream(socket.getOutputStream()));
			
			// tell the new client what position he is sitting at
			IMessage joinRequestResponse = new Message(MessageType.JOIN_REQUEST, pos);
			sendMessage(joinRequestResponse, pos);
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}

	}
	
	public void handleIMessage(IMessage message) {
		message.print();
		switch (message.getMessageType()) {
		case BID_INFO: // server should never receive a bid info message only send them
			break;
		case TRUMP_INFO: // server should never receive a trump info message only send them
			break;
		case PLAYER_INFO: // server should never receive a player info message only send them
			break;
		case BID_MESSAGE: // A player sent a bid to the server
			Integer bid = (Integer) message.getArguements();
			match.bidPlaced(bid);
			break;
		case SUIT_MESSAGE:
			Suit suit = (Suit) message.getArguements();
			match.setCurrentTrump(suit);
			break;
		case PLAY_MESSAGE:
			Card card = (Card) message.getArguements();
			match.cardPlayed(card);
			break;
		case TRADE_MESSAGE:
			@SuppressWarnings("unchecked")
			List<Card> cards = (List<Card>) message.getArguements();
			try {
				match.cardsTraded(cards);
			} catch (OutOfCardsException e) {
				e.printStackTrace();
			}
			break;
		case DEAL_MESSAGE:
			// no arguements
			try {
				match.dealCards();
			} catch (OutOfCardsException e) {
				e.printStackTrace();
			}
			break;
		case SIT_MESSAGE:
			IPlayer player = (IPlayer) message.getArguements();
			match.addPlayer(player);
			break;
			
		case JOIN_REQUEST:
			// no arguements
			
		}
	}
	
	public void sendMessage(IMessage message, PlayerPosition pos) 
	{
		if (outputStreams.get(pos) == null) {
			((RobotPlayer)match.getPlayerAtPosition(pos)).handleMessage(message);
		} else {
			try 
			{
				outputStreams.get(pos).reset();
				outputStreams.get(pos).writeObject(message);
				outputStreams.get(pos).flush();
			} 
			catch (IOException e) 
			{
				e.printStackTrace();
			}
		}
	}
	public void sendMessage(IMessage message) {
		for(PlayerPosition pos : outputStreams.keySet())
		{
			sendMessage(message, pos);
		}
	}
	
	public static void main(String[] args)
	{
		
	}

	public class ServerThread extends Thread 
	{
		private ObjectInputStream ois;
		private SetbackServer server;
		
		public ServerThread(Socket socket, SetbackServer server) throws IOException 
		{
			this.server = server;
			ois = new ObjectInputStream(socket.getInputStream());
		}
				
		@Override
		public void run() {
			super.run();
			boolean shouldContinue = true;
			while (shouldContinue) {
				try {
					Object o = ois.readObject();
					IMessage message = (IMessage) o;
					server.handleIMessage(message);
//					System.out.println(message.getMessageType().toString());
//					SetbackServer.sendMessage(message);
				} catch (SocketException se) {
					System.out.println("received a socket exception, quitting");
					shouldContinue = false;
				} catch (IOException e) {
					e.printStackTrace();
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} 
				
			}
		}
	}
}
